package yunjiao.javatutorials.designpatterns.combinator;



import java.util.Arrays;
import java.util.Objects;

import static yunjiao.javatutorials.designpatterns.combinator.Validators.and;
import static yunjiao.javatutorials.designpatterns.combinator.Validators.from;


/**
 * 用户校验
 *
 * @author yangyunjiao
 */
public class UserValidator {
    // 使用基础 Combinator 构建小的、具体的验证规则
    private static final Validator<String> notNullAndLongerThan3 =
            and(from(Objects::nonNull, "Name cannot be null"),
                    from(s -> s.length() > 3, "Name must be longer than 3 characters"));

    private static final Validator<String> containsAtSymbol =
            from(s -> s != null && s.contains("@"), "Email must contain '@'");

    private static final Validator<Integer> isAdult =
            from(age -> age >= 18, "Age must be >= 18");

    // 组合成最终的用户验证器
    public static final Validator<User> userValidator = user -> {
        // 对 user 的各个字段应用相应的验证器，然后用 `and` 组合结果
        ValidationResult nameResult = notNullAndLongerThan3.validate(user.getName());
        ValidationResult emailResult = containsAtSymbol.validate(user.getEmail());
        ValidationResult ageResult = isAdult.validate(user.getAge());

        // 合并所有结果
        return and(and(
                        t -> nameResult, // 将这些结果包装成 Validator
                        t -> emailResult
                ),
                t -> ageResult
        ).validate(user); // 执行合并后的验证器
    };

    // 更优雅的写法：可以创建一个 `combine` Combinator 来接受多个验证器
    @SafeVarargs
    public static <T> Validator<T> combine(Validator<T>... validators) {
        return Arrays.stream(validators)
                .reduce(Validators.valid(), Validators::and);
    }

    // 使用 combine 的优雅版本
    public static final Validator<User> elegantUserValidator =
            combine(
                    user -> notNullAndLongerThan3.validate(user.getName()),
                    user -> containsAtSymbol.validate(user.getEmail()),
                    user -> isAdult.validate(user.getAge())
            );
}

